#include "mprpcchannel.h"
#include "mprpcapplication.h"
#include "rpcheader.pb.h"

// socket编程头文件四件套
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <unistd.h>
#include <string>
#include <google/protobuf/service.h>
#include <google/protobuf/descriptor.h>

void MprpcChannel::CallMethod(const google::protobuf::MethodDescriptor *method,
                              google::protobuf::RpcController *controller,
                              const google::protobuf::Message *request,
                              google::protobuf::Message *response,
                              google::protobuf::Closure *done)
{
    const google::protobuf::ServiceDescriptor *sd = method->service();
    std::string service_name = sd->name();
    std::string method_name = method->name();

    // 获取参数的序列化字符串args_str
    uint32_t args_size = 0;
    std::string args_str;
    if (request->SerializeToString(&args_str))
    {
        args_size = args_str.size();
    }
    else
    {
        // std::cout << "serialize request error!" << std::endl;
        controller->SetFailed("serialize request error!");
        return;
    }

    // 定义rpc请求
    // header_size + service_name + method_name + args_size + args_str
    mprpc::RpcHeader rpcheader;
    rpcheader.set_service_name(service_name);
    rpcheader.set_method_name(method_name);
    rpcheader.set_args_size(args_size);

    uint32_t header_size = 0;
    std::string rpc_header_str;
    if (rpcheader.SerializeToString(&rpc_header_str))
    {
        header_size = rpc_header_str.size();
    }
    else
    {
        // std::cout << "serialize rpcheader error!" << std::endl;
        controller->SetFailed("serialize rpcheader error!");
        return;
    }

    // 组织待发送的rpc请求
    std::string rpc_send_str;
    rpc_send_str.insert(0, std::string((char *)&header_size, 4));
    rpc_send_str += rpc_header_str;
    rpc_send_str += args_str;

    // 打印调试信息
    std::cout << "=========================================" << std::endl;
    std::cout << "header_size: " << header_size << std::endl;
    std::cout << "rpc_header_str: " << rpc_header_str << std::endl;
    std::cout << "service_name: " << service_name << std::endl;
    std::cout << "method_name: " << method_name << std::endl;
    std::cout << "args_size: " << args_size << std::endl;
    std::cout << "args_str: " << args_str << std::endl;
    std::cout << "=========================================" << std::endl;

    // 使用TCP编程完成rpc调用
    int clientfd = socket(PF_INET, SOCK_STREAM, 0);
    if (-1 == clientfd)
    {
        // std::cout << "create clientfd error!" << std::endl;
        controller->SetFailed("create clientfd error!");
        return;
        // exit(EXIT_FAILURE);
    }

    // 读取配置文件信息
    std::string ip = MprpcApplication::GetInstance().GetConfig().GetValue("rpcserverip");
    uint16_t port = atoi(MprpcApplication::GetInstance().GetConfig().GetValue("rpcserverport").c_str());

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip.c_str());

    // 连接
    if (-1 == connect(clientfd, (struct sockaddr *)&server, sizeof server))
    {
        // std::cout << "connect error!" << std::endl;
        close(clientfd);
        controller->SetFailed("connect error!");
        return;
        // exit(EXIT_FAILURE);
    }

    // 发送rpc请求
    if (-1 == send(clientfd, rpc_send_str.c_str(), rpc_send_str.size(), 0))
    {
        char buf[64] = {0};
        sprintf(buf, "send error! errno: %d", errno);
        // std::cout << "send error! errno: " << errno << std::endl;
        controller->SetFailed(buf);
        close(clientfd);
        return;
    }

    // 接收响应
    char recv_buf[1024] = {0};
    ssize_t n = recv(clientfd, recv_buf, sizeof recv_buf, 0);
    if (-1 == n)
    {
        // std::cout << "recv error! errno: " << errno << std::endl;
        char buf[64] = {0};
        sprintf(buf, "recv error! errno: %d", errno);
        controller->SetFailed(buf);
        return;
        close(clientfd);
    }

    // std::string response_str(recv_buf, 0, n);    // 遇到'\0'就停止截取了
    // 反序列化响应
    // if (!response->ParseFromString(response_str))
    if (!response->ParseFromArray(recv_buf, n))
    {
        // std::cout << "parse error! response_str: " << recv_buf << std::endl;
        std::string buf;
        sprintf((char*)buf.c_str(), "parse error! response_str:  %s", recv_buf);
        controller->SetFailed(buf);
        close(clientfd);
        return;
    }
    close(clientfd);
}